package com.wonders.common.ws.client;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.PrivateKey;

import javax.xml.namespace.QName;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.encoding.XMLType;

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.wonders.common.config.manager.instance.PropertiesManager;
import com.wonders.common.constant.CommonConstant;
import com.wonders.common.parse.jaxb.JaxbService;
import com.wonders.common.ws.constant.XtptConstant;
import com.wonders.common.ws.entity.vo.XtptMsg;
import com.wonders.common.ws.mapping.bean.global.Head;
import com.wonders.common.ws.util.XtptUtil;
import com.wonders.framework.exception.FrameworkException;
import com.wonders.framework.util.StreamUtil;
import com.wonders.framework.util.security.RsaUtil;

/**
 * 协同平台客户端
 * 
 * @author WuBin
 * 
 */
@Component
public class XtptWsClient {

	private Logger logger = LoggerFactory.getLogger(XtptWsClient.class);

	@Autowired
	private JaxbService jaxbService;

	@Autowired
	private PropertiesManager propertiesManager;

	/**
	 * 接口调用私钥
	 */
	private PrivateKey privateKey;

	/**
	 * 获取私钥
	 * 
	 * @return
	 */
	private PrivateKey getPrivateKey() {
		if (privateKey == null) {
			privateKey = RsaUtil.parsePrivateKey(propertiesManager
					.getXtptPrivateKey());
		}
		return privateKey;
	}

	/**
	 * 接口调用
	 * 
	 * @param key
	 *            业务主键
	 * @param reqDate
	 *            数据
	 * @return 调用结果
	 */
	public XtptMsg request(String key, Object reqDate) {
		if (StringUtils.isEmpty(key) || reqDate == null) {
			throw new FrameworkException("接口调用参数不足");
		}
		Head globalHead = XtptUtil.generateRequestHead(key);
		XtptMsg xtptRequest = new XtptMsg();
		xtptRequest.setHeadXml(jaxbService.toXml(XtptConstant.GLOBAL_HEAD,
				CommonConstant.Interaction.REQ, globalHead));
		xtptRequest.setBodyXml(jaxbService.toXml(key,
				CommonConstant.Interaction.REQ, reqDate));
		logger.info("请求报文头:{}, 请求报文体:{}", xtptRequest.getHeadXml(),
				xtptRequest.getBodyXml());
		byte[] request = packRequest(xtptRequest);
		byte[] response = callService(request);
		XtptMsg xtptResponse = resovleResponse(key, response);
		logger.info("响应报文头:{}, 响应报文体:{}", xtptResponse.getHeadXml(),
				xtptResponse.getBodyXml());
		return xtptResponse;
	}

	/**
	 * 组装请求
	 * 
	 * @param xtptRequest
	 *            请求数据
	 * @return 请求数据
	 */
	private byte[] packRequest(XtptMsg xtptRequest) {
		ByteArrayOutputStream byteArrayOutputStream = null;
		DataOutputStream dataOutputStream = null;
		try {
			byteArrayOutputStream = new ByteArrayOutputStream();
			dataOutputStream = new DataOutputStream(byteArrayOutputStream);
			byte[] head = xtptRequest.getHeadXml().getBytes(
					XtptConstant.ENCODING);
			byte[] body = xtptRequest.getBodyXml().getBytes(
					XtptConstant.ENCODING);
			dataOutputStream.writeShort(head.length);
			dataOutputStream.writeInt(body.length);
			dataOutputStream.writeByte(XtptConstant.SIGNATURE_FLAG);
			dataOutputStream.write(head);
			dataOutputStream.write(body);
			dataOutputStream.write(RsaUtil.sign(getPrivateKey(), head, body));
			dataOutputStream.flush();
		} catch (Exception e) {
			throw new FrameworkException("组装请求数据失败", e);
		} finally {
			if (dataOutputStream != null) {
				try {
					dataOutputStream.close();
				} catch (IOException e) {
					logger.error("关闭流失败", e);
				}
			}
		}
		return byteArrayOutputStream.toByteArray();
	}

	/**
	 * 调用协同平台
	 * 
	 * @param request
	 *            请求数据
	 * @return 响应数据
	 */
	private byte[] callService(byte[] request) {
		try {
			Service service = new Service();
			Call call = (Call) service.createCall();
			call.setTargetEndpointAddress(propertiesManager.getXtptUrl());
			call.setOperationName(new QName(
					"http://jws.wsscclib.wondersgroup.com", "dispatch"));
			call.addParameter("request", XMLType.XSD_BASE64, ParameterMode.IN);
			call.setReturnType(XMLType.XSD_BASE64);
			byte[] ret = (byte[]) call.invoke(new Object[] { request });
			return ret;
		} catch (Exception e) {
			throw new FrameworkException("接口调用失败", e);
		}
	}

	/**
	 * 解析响应数据
	 * 
	 * @param key
	 *            业务主键
	 * @param response
	 *            响应内容
	 * @param encoding
	 *            编码
	 * @return 调用结果
	 */
	private XtptMsg resovleResponse(String key, byte[] response) {
		DataInputStream dataInputStream = null;
		try {
			ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
					response);
			dataInputStream = new DataInputStream(byteArrayInputStream);
			short headlen = dataInputStream.readShort();
			int bodylen = dataInputStream.readInt();
			dataInputStream.readByte();
			byte[] headbytes = StreamUtil.read(dataInputStream, headlen);
			byte[] bodybytes = null;
			if (bodylen > 0) {
				bodybytes = StreamUtil.read(dataInputStream, bodylen);
			}
			XtptMsg xtptResponse = new XtptMsg();
			Head head = (Head) jaxbService.fromXML(XtptConstant.GLOBAL_HEAD,
					CommonConstant.Interaction.REQ, new String(headbytes,
							XtptConstant.ENCODING));
			xtptResponse.setHead(head);
			XtptUtil.parseResponseHead(xtptResponse, head);
			if (bodybytes != null) {
				xtptResponse.setBody(jaxbService.fromXML(key,
						CommonConstant.Interaction.REQ, new String(bodybytes,
								XtptConstant.ENCODING)));
			}
			return xtptResponse;
		} catch (Exception e) {
			throw new FrameworkException("解析响应数据失败", e);
		} finally {
			if (dataInputStream != null) {
				try {
					dataInputStream.close();
				} catch (IOException e) {
					logger.error("关闭流失败", e);
				}
			}
		}
	}

}
